;;===============================================================
;; Trie unit tests
;;===============================================================
(ns strclj.trie-test
  (:use [strclj.trie :as src]
        [clojure.test]
        [objects.node]
        [strclj.core-test])
  (:import [objects Node])
)

(deftest test-node-make
  (testing "Node object creation"
	  (let [init-with-dict (node-make (array-map))
         init-without-dict (node-make)]
	    (is (= (node-get-dict init-with-dict)
	           (array-map))
	    "With parameter")
      (is (nil? (node-get-dict init-without-dict) )
      "Without parameter")
	  )
  )
)


(deftest test-get-children
  (testing "get-children"
    (let [child (node-make)
          root (node-make (array-map))]
      ; Adding child
      (node-set-dict! root (assoc-in (node-get-dict root) [:children \a] child))
      ; Test root children contents
      (is (= (get-children root) {\a child}))
      ; Child has not children
      (is (= (get-children child) nil))
    )
  )
)

(deftest test-get-child
  (testing "get-child"
    (let [child (node-make)
          root (node-make (array-map))]
      ; Adding child
      (node-set-dict! root (assoc-in (node-get-dict root) [:children \a] child))
      ; Existing child retrieval
      (is (= (get-child root \a) child))
      ; Nonexistant child retrieval
      (is (= (get-child root \b) nil))
    )
  )
)

(deftest test-update-max-length
  (testing "update-max-length"
    (let [child (node-make)
          root (node-make (array-map))]
      ; Set max length
      (@#'src/update-max-length! root 4)
      ; Updating to 5
      (@#'src/update-max-length! root 5)
      (is (= (:max-length (node-get-dict root)) 5))
      ; Try updating to 3
      (@#'src/update-max-length! root 3)
      ; Should stay 5
      (is (= (:max-length (node-get-dict root)) 5))
    )
  )
)

(deftest test-flag-finish-node
  (testing "flag-finish-node"
    (let [root (node-make)]
      ; No :finish true at default
      (is (= (:finish (node-get-dict root)) nil))
      ; Flag node
      (@#'src/flag-finish-node! root) 
      (is (= (:finish (node-get-dict root)) true))
    )
  )
)

(deftest test-get-finish-flag
  (testing "get-finish-flag"
    (let [root (node-make)]
      ; No :finish true at default
      (is (= (@#'src/get-finish-flag root) nil))
      ; Add flag
      (@#'src/flag-finish-node! root)
      ; Recheck
      (is (= (@#'src/get-finish-flag root) true))
    )
  )
)


(deftest test-node-add
  (testing "node-add (Chaining kids to a node, also acts as a getter)"
	  (let [root (node-make)
          node (node-make (array-map))
          child (@#'src/node-add! root \a)
          another_child (@#'src/node-add! root \b)]
      ; Testing creation via node-add
	    (is (= child node))
      ; Testing get via node-add
	    (is (identical? (@#'src/node-add! root \a) child))
      ; Comparing two children
      (is (= child another_child))
      (is (not (identical? another_child child)))
	  )
  )
)

(with-private-fns [strclj.trie [get-children node-add!]]
	(deftest test-trie-add
	  (testing "trie-add (Adding a word to Trie)"
		  (let [root (node-make)
	          root-dict (trie-add! root "hello")
	          trimmed-root (node-make (trie-add! (node-make) "ello"))]
	     ; Invocation with nil
	      (is (= nil (trie-add! nil "whatsup")))
	      ; Testing contents
		    (is (= (get-children (node-add! root \h))
	             (get-children trimmed-root)
	          )
	      )
	     ; Testing structure
	     (is (= 5 (:max-length (node-get-dict root))))
	     (is (= 1 (count (get-children root)))) 
		  )
	  )
	)
)

(deftest test-trie-get
  (testing "trie-get"
	  (let [root (node-make)
          root-dict (trie-add! root "hello")
          trimmed-root (node-make (trie-add! (node-make) "ello"))]
     ; Invocation with nil root
      (is (= nil (trie-get nil "whatsup")))
     ; Existing word
      (is (= (node-make (array-map :finish true)) (trie-get root "hello")))
     ; Nonexistant word
      (is (= nil (trie-get root "whatsup")))
	  )
  )
)


(deftest test-trie-make
  (testing "trie-make (Creation of new Trie with list of patterns)"
	  (let [root (trie-make ["abcd" "kmabco" "ga" "gs"])]
      ; Testing structure
      (is (= 6 (:max-length (node-get-dict root))))
      (is (= 3 (count (get-children root))))
      ; Root's children
      (are [child children-number]
        (let [child-node (get-child root child)
              children-count (count (get-children child-node))]
          (and (instance? Node child-node) (= children-number children-count))
        )
        \a 1
        \k 1
        \g 2
      )
	  )
  )
)




